Parse __eh_frame DWARF info on macOS for per-PC frame descriptions#430
Parse __eh_frame DWARF info on macOS for per-PC frame descriptions#430
Conversation
CI Test ResultsRun: #24180892588 | Commit:
Status Overview
Legend: ✅ passed | ❌ failed | ⚪ skipped | 🚫 cancelled Summary: Total: 32 | Passed: 32 | Failed: 0 Updated: 2026-04-09 09:14:05 UTC |
There was a problem hiding this comment.
Pull request overview
Adds macOS support for parsing raw __eh_frame DWARF CFI to produce per-PC frame descriptions, improving unwinding for binaries that don’t provide __unwind_info (e.g., GCC-built libs).
Changes:
- Introduces a
DwarfParserconstructor +parseEhFrame()path to parse linear.eh_frame/__eh_framewithout an.eh_frame_hdrindex. - Extends macOS Mach-O parsing to locate
__eh_frameand populateCodeCache’s DWARF table; also addsSymbols::clearParsingCaches()for macOS. - Adds new gtest unit tests for
parseEhFrame().
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
ddprof-lib/src/main/cpp/dwarf.h |
Declares the new raw-eh-frame constructor and parseEhFrame() API. |
ddprof-lib/src/main/cpp/dwarf.cpp |
Implements linear __eh_frame parsing and augmentation handling. |
ddprof-lib/src/main/cpp/symbols_macos.cpp |
Finds __eh_frame in Mach-O __TEXT and wires parsed DWARF into CodeCache. |
ddprof-lib/src/test/cpp/dwarf_ut.cpp |
Adds unit tests exercising the new linear .eh_frame parsing path. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Scan-Build Report
Bug Summary
Reports
|
||||||||||||||||||||||||||||||||||||
dfe7b83 to
4466cfb
Compare
Revert static thread_local jmp_buf in walkVM — thread_local access via __tls_get_addr is not async-signal-safe in a dlopen'd agent. Suppress core.StackAddressEscape in scan-build instead: the jmp_buf address is always restored to saved_exception before walkVM returns. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Add overflow guard before record_end in parseEhFrame - Guard _ptr accesses in short CIE body path - Add bounded getLeb/getSLeb overloads; use in parseEhFrame - Extract DwarfParser::init() to remove constructor duplication - Demote _eh_frame/_eh_frame_size to locals in MachOParser::parse() - Add bounds-guard tests: TruncatedRecord, ShortCieBody, FdeAugDataOverrun - Document table() ownership, CIE/FDE layout assumptions, EOF handling Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Merge all GitLab CI config from java-profiler-build repository - Register project with ADMS and add octo-sts policies - Move gitlab/ to .gitlab/ for unified CI structure - Switch to java-profiler IAM service account and SSM prefix - Flatten pipeline and fix cross-cutting CI issues - Gate push pipelines on GitHub PR existence; cancel gracefully when no PR - Fix ARM runner tags: arch:arm64 instead of runner:apm-k8s-arm-metal PROF-14208
Agent-Logs-Url: https://github.com/DataDog/java-profiler/sessions/dce1b1b9-1d7e-4322-90be-421ddc8185c6 Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jbachorik <738413+jbachorik@users.noreply.github.com>
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.33.0 to 4.35.1. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](github/codeql-action@b1bff81...c10b806) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.35.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [DataDog/dd-octo-sts-action](https://github.com/datadog/dd-octo-sts-action) from 1.0.3 to 1.0.4. - [Release notes](https://github.com/datadog/dd-octo-sts-action/releases) - [Commits](DataDog/dd-octo-sts-action@acaa02e...96a2546) --- updated-dependencies: - dependency-name: DataDog/dd-octo-sts-action dependency-version: 1.0.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the gradle-minor group with 3 updates: [com.diffplug.spotless:spotless-plugin-gradle](https://github.com/diffplug/spotless), [gradle-wrapper](https://github.com/gradle/gradle) and com.diffplug.spotless. Updates `com.diffplug.spotless:spotless-plugin-gradle` from 8.3.0 to 8.4.0 - [Release notes](https://github.com/diffplug/spotless/releases) - [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md) - [Commits](diffplug/spotless@gradle/8.3.0...gradle/8.4.0) Updates `gradle-wrapper` from 9.4.0 to 9.4.1 - [Release notes](https://github.com/gradle/gradle/releases) - [Commits](gradle/gradle@v9.4.0...v9.4.1) Updates `com.diffplug.spotless` from 8.3.0 to 8.4.0 --- updated-dependencies: - dependency-name: com.diffplug.spotless:spotless-plugin-gradle dependency-version: 8.4.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gradle-minor - dependency-name: gradle-wrapper dependency-version: 9.4.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: gradle-minor - dependency-name: com.diffplug.spotless dependency-version: 8.4.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gradle-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/cache](https://github.com/actions/cache) from 5.0.3 to 5.0.4. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](actions/cache@cdf6c1f...6682284) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 5.0.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the gradle-minor group in /build-logic with 1 update: [com.diffplug.spotless:spotless-plugin-gradle](https://github.com/diffplug/spotless). Updates `com.diffplug.spotless:spotless-plugin-gradle` from 8.3.0 to 8.4.0 - [Release notes](https://github.com/diffplug/spotless/releases) - [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md) - [Commits](diffplug/spotless@gradle/8.3.0...gradle/8.4.0) --- updated-dependencies: - dependency-name: com.diffplug.spotless:spotless-plugin-gradle dependency-version: 8.4.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gradle-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
validate-jfr-conformance.sh and its companion files (conformance.yaml, thresholds.env, validate-jfr.jfrs) were referenced by .gitlab/dd-trace-integration/run-integration-test.sh but never ported over during the CI migration (b7410c6). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Include dd-trace-integration pipeline in .gitlab-ci.yml - Fix ProfilerTestApp.java path (.gitlab/test-apps/ not test-apps/) - Export DDPROF_COMMIT_BRANCH/SHA from prepare.sh for integration scripts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace hardcoded amd64 image digest with multi-arch dd-octo-sts-ci-base. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use Datadog MagicMirror proxy (same as dd-trace-java) when ORG_GRADLE_PROJECT_mavenRepositoryProxy is set in CI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- getLeb(end): u32 cast + shift<32 guard to prevent UB - parseEhFrame: use LINKED_FRAME_CLANG_SIZE for sentinel addRecord - CodeCache copy ctor: guard malloc/memcpy when dwarf_table_length==0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
What
Parse raw
__eh_frameDWARF CFI data on macOS to provide per-PC frame descriptions for GCC-built libraries, improving stack unwinding accuracy for functions with non-standard frame layouts (leaf functions,-fomit-frame-pointer).Changes
ddprof-lib/src/main/cpp/dwarf.h/dwarf.cppDwarfParserconstructor accepting a raw(eh_frame, size)pair (no binary-search index).parseEhFrame(): linearly iterates CIE/FDE records, extracts code/data alignment from each CIE, decodes per-PC frame descriptions from FDEs, thenqsorts the result._has_z_augmentationfield: set when the CIE augmentation string starts with'z'. The FDE augmentation-data-length LEB field is only present in that case; guarding the skip prevents corrupting the instruction stream for CIEs with empty or non-zaugmentation. The parser assumes a single CIE per module — the DWARF spec allows multiple CIEs with different augmentation strings, but macOS binaries compiled by clang always emit one CIE per module and this path is only exercised for macOS__eh_framesections.detectedDefaultFrame()tosetDwarfTable(), matching the Linux path and correctly selecting the clang frame layout on aarch64.getLeb()/getSLeb()calls to guard against malformed or truncated__eh_framedata.ddprof-lib/src/main/cpp/symbols_macos.cpp__eh_framesection in the__TEXTsegment during Mach-O parsing.DWARF_SUPPORTEDand the section is present, construct aDwarfParserand callcc->setDwarfTable()with the detected default frame.Symbols::clearParsingCaches()definition (fixes linker error on macOS).ddprof-lib/src/test/cpp/dwarf_ut.cpp(new)parseEhFrame(): empty section, terminator-only, CIE-only, and CIE+FDE.Why
On macOS, GCC-built shared libraries (
libgcc, Homebrew packages) emit__eh_framewith standard DWARF CFI, but no__unwind_info. Previously the profiler fell back to a single library-wide heuristic frame layout for these libraries. Parsing the DWARF FDE table yields exact CFA/FP/PC rules per instruction address, eliminating unwinding failures at function prologues and epilogues.JIRA: PROF-14088